package org.devastra.arcinspect.eval;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.devastra.arcinspect.core.data.EntityInfo;
import org.devastra.arcinspect.core.data.EntityType;
import org.devastra.arcinspect.core.data.PackageInfo;
import org.devastra.arcinspect.core.data.cache.EntityInfoCache;
import org.devastra.arcinspect.plan.ArchitecturePlan;

public class DependencyEvaluator {
	
	private ArchitecturePlan plan;
	private Map<EntityInfo, List<EntityInfo>> reffering2RefferedViolationMap;
	
	public DependencyEvaluator(ArchitecturePlan _plan) {
		plan = _plan;
		reffering2RefferedViolationMap = new HashMap<EntityInfo, List<EntityInfo>>();
	}
	
	public void checkDependency() {
		//plan = _plan;
		reffering2RefferedViolationMap.clear();
		
		for(EntityInfo entity : EntityInfoCache.getAllEntityInfo()) {
			switch(entity.getType()) {
			case CLASS:
			case INTERFACE:
				checkEntityDependency(entity);
				break;
			}
		}
	}
	
	private void checkEntityDependency(EntityInfo _entity) {
		PackageInfo entityPkg = getEntityPackage(_entity);
		List<EntityInfo> refEntityList = _entity.getReferencedEntityInfo();
		
		int entityPkgLoc = plan.getPackageLocation(entityPkg.getName());
		for(EntityInfo refEntity : refEntityList) {
			PackageInfo refEntityPkg = getEntityPackage(refEntity);
			
			int refEntityLoc = plan.getPackageLocation(refEntityPkg.getName());
			
			if(entityPkgLoc > refEntityLoc) { //not allowed
				List<EntityInfo> refList = reffering2RefferedViolationMap.get(_entity);
				if(refList == null) {
					refList = new ArrayList<EntityInfo>();
					reffering2RefferedViolationMap.put(_entity, refList);
				}
				refList.add(refEntity);
				//reffering2RefferedViolationMap.put(_entity, refEntity);
			}
		}
	}
	
	private PackageInfo getEntityPackage(EntityInfo _entity) {
		PackageInfo pkgInfo = null;
		
		if(_entity != null && !EntityType.UNKNOWN.equals(_entity.getType())) {
			EntityInfo currEntity = _entity;
			while(!EntityType.PACKAGE.equals(currEntity.getType())) {
				currEntity = currEntity.getParent();
			}
			
			if(currEntity != null) {
				pkgInfo = (PackageInfo) currEntity;
			}
		}
		return pkgInfo;
		
	}
	
	class EntityRef implements Comparable<EntityRef> {
		private EntityInfo refferingEntity;
		private EntityInfo refferedEntity;
		
		public EntityRef(EntityInfo _reffering, EntityInfo _reffered) {
			refferingEntity = _reffering;
			refferedEntity = _reffered;
		}
		
		public String getSignature() {
			return refferingEntity.getId()+"-"+refferedEntity.getId();
		}
		
		@Override
		public int compareTo(EntityRef _other) {
			
			return this.getSignature().compareTo(_other.getSignature());
		}
	}
}
